/*
 * =============================================================
 *
 *        Project:  apue
 *
 *       Filename:  sleep.c
 *
 *         Editor:  vim :set et ts=2 sts=2 sw=2
 *
 *         Author:  Martin Y. Yang , yang@libpix.org
 *
 *    Description:  
 *
 * =============================================================
 */

/**
 * @file
 * @brief Figure 10.29 Reliable implementation of sleep
 */

#include "apue.h"

static void sig_alrm(int signo)
{
  /* nothing to do, just returning wakes up sigsuspend() */
}

unsigned int sleep3(unsigned int nsecs)
{
  struct sigaction newact, oldact;
  sigset_t newmask, oldmask, suspmask;
  unsigned int unslept;

  /* set our handler, save previous information */
  newact.sa_handler = sig_alrm;
  sigemptyset(&newact.sa_mask);
  newact.sa_flags = 0;
  sigaction(SIGALRM, &newact, &oldact);

  /* block SIGALRM and save current signal mask */
  sigemptyset(&newmask);
  sigaddset(&newmask, SIGALRM);
  sigprocmask(SIG_BLOCK, &newmask, &oldmask);

  alarm(nsecs);
  suspmask = oldmask;
  sigdelset(&suspmask, SIGALRM);                /* make sure SIGALRM isn't blocked */
  sigsuspend(&suspmask);                        /* wait for any signal to be caught */

  /* some signal has been caught, SIGALRM is now blocked */

  unslept = alarm(0);
  sigaction(SIGALRM, &oldact, NULL);            /* reset previous action */

  /* reset signal mask, which unblocks SIGALRM */
  sigprocmask(SIG_SETMASK, &oldmask, NULL);
  return unslept;
}


